﻿using System;
using DomainModel.Domain.Model;
using DomainModel.Domain.Model.MessageTypeModel;
using DomainModel.Domain.Model.ServiceModel;
using DomainModel.Domain.Model.SubscriptionModel;
using EsbMonitor.Ninject;
using EsbMonitorMessages.Events;
using NServiceBus;

namespace EsbMonitor.Handlers
{
    public class SubscriptionRegisteredEventHandler : IHandleMessages<ISubscriptionRegistered>
    {
        private const int NoServiceFailMax = 5;
        private const int NoMessageTypeFailMax = 5;

        public IBus Bus { get; set; }

        public void Handle(ISubscriptionRegistered message)
        {
            var servicesRepository = KernelContainer.Get<IServicesRepository>();
            var subscriptionsRepository = KernelContainer.Get<ISubscriptionsRepository>();

            QueueInfo publisherQueue = new QueueInfo(message.PublisherInfo.InputQueue.QueueName);
            QueueInfo subscriberQueue = new QueueInfo(message.SubscriberInputQueue.QueueName);

            Service publisher = servicesRepository.Get(publisherQueue);
            Service subscriber = servicesRepository.Get(subscriberQueue);

            if (publisher == null || subscriber == null)
            {
                HandleNoServiceSituation();
                return;
            }

            MessageType messageType = publisher.FindMessageType(message.TypeName.MessageAssemblyInfo.MessageAssemblyName, message.TypeName.TypeName);

            if (messageType == null)
            {
                HandleNoMessageTypeSituation();
                return;
            }

            Subscription subscription = subscriptionsRepository.Get(messageType, publisher, subscriber) ?? new Subscription(subscriptionsRepository.NextSubscriptionId())
                                                                                                               {
                                                                                                                 MessageType = messageType,
                                                                                                                 Publisher = publisher,
                                                                                                                 Subscriber = subscriber,
                                                                                                                 RegisterDate = DateTime.Now
                                                                                                               };

            SubscriberRole subscriberRole = new SubscriberRole(servicesRepository.NextServiceRoleId());
            subscriberRole.CreateModifyInfo = new CreateModifyInfo
                                                  {
                                                      Created = DateTime.Now,
                                                      LastModified = DateTime.Now
                                                  };

            subscriberRole.Subscription = subscription;
            
            subscriber.AddServiceRole(subscriberRole);;

            subscriptionsRepository.Store(subscription);

            servicesRepository.Store(subscriber);
        }

        private void HandleNoMessageTypeSituation()
        {
            HandleLaterUnlessMaxFailTimesHasBeenReached("failed_no_message_type", NoMessageTypeFailMax);
        }

        private void HandleNoServiceSituation()
        {
            HandleLaterUnlessMaxFailTimesHasBeenReached("failed_no_service", NoServiceFailMax);
        }

        private void HandleLaterUnlessMaxFailTimesHasBeenReached(string key, int max)
        {
            if (!Bus.CurrentMessageContext.Headers.ContainsKey(key))
            {
                Bus.CurrentMessageContext.Headers.Add(key, "1");
                Bus.HandleCurrentMessageLater();
                return;
            }

            int count = int.Parse(Bus.CurrentMessageContext.Headers[key]);

            if (count != max)
            {
                Bus.CurrentMessageContext.Headers[key] = (count + 1).ToString();
                Bus.HandleCurrentMessageLater();
            }
        }
    }
}